package com.qf.index;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import cn.hutool.json.JSONUtil;

import java.sql.SQLException;
import java.util.*;

/**
 * jcr的期刊，因期刊变更等原因，可能存在不同的期刊含有相同的ISSN号或期刊名称，对此需要进行合并，本程序的功能就是给予合并，并产生一张不重复的新的期刊清单，用于后续的期刊检索及下载。
 * 贾新志 2025.02.18
 */

public class mergeJournal {

    public static void main(String[] args) throws SQLException {
        String newDataName = "scholar_25_01.";
        String jcrJourDetailTable = newDataName + "jcr_jour_detail_2019_2023_back";
        String noRepeatTable = newDataName + "jcr_jour_detail_2019_2023_back_1";
        String detailTable = newDataName + "jcr_jour_detail_2019_2023_back_2";

        readTable(jcrJourDetailTable, "id", "journal_name`,`abbr_journal`,`issn`,`eissn", noRepeatTable, detailTable);

    }

    public static void readTable(String jcrJourDetailTable, String autoId, String field, String noRepeatTable, String detailTable) throws SQLException {
        int onePageNum = 1000;
        List<Entity> tableNum = Db.use().query("select count(1) as count from " + jcrJourDetailTable);
        String spl = "ĺļ";
        Set<String> equalSet = new HashSet<>();
        Map<List<String>, Integer> journalListAndAutoIdMap = new HashMap<>();
        Db.use().execute("truncate table " + noRepeatTable);
        Db.use().execute("truncate table " + detailTable);
        if (tableNum.get(0).getInt("count") > 0) {
            int tableMax = Db.use().queryNumber("select max(" + autoId + ") from " + jcrJourDetailTable).intValue();
            Collection<Integer> tableList = new ArrayList<>();
            NumberUtil.appendRange(0, tableMax + onePageNum, onePageNum, tableList);
            for (Integer startId : tableList) {
                List<Entity> tableData = Db.use().query("select `" + autoId + "`,`" + field + "` from " + jcrJourDetailTable + " where " + autoId + " between " + startId + " and " + (startId + onePageNum - 1));
                for (Entity entry : tableData) {
                    String full = Utils.getStrField(entry, "journal_name").toLowerCase().trim();
                    String abbr = Utils.getStrField(entry, "abbr_journal").toLowerCase().trim();
                    String issn = Utils.getStrField(entry, "issn").toLowerCase().trim();
                    String eissn = Utils.getStrField(entry, "eissn").toLowerCase().trim();
                    int id = Utils.getIntField(entry, autoId);
                    Set<String> set = new HashSet<>();
                    if (full.length() > 2) {
                        set.add(full);
                    }
                    if (abbr.length() > 2) {
                        set.add(abbr);
                    }
                    if (issn.length() == 9 && issn.charAt(4) == '-') {
                        set.add(issn);
                    }
                    if (eissn.length() == 9 && eissn.charAt(4) == '-') {
                        set.add(eissn);
                    }
                    if (!set.isEmpty()) {
                        equalSet.add(CollUtil.join(set, spl));
                        List<String> list = new ArrayList<>(set);
                        Collections.sort(list);
                        journalListAndAutoIdMap.put(list, id);
                    }
                }
            }
        }
        // 将不重复的期刊插入到单独的一张表中，含期刊各元素以及aid号。
        for (Map.Entry<List<String>, Integer> entry : journalListAndAutoIdMap.entrySet()) {
            try {
                Db.use().insert(Entity.create(noRepeatTable).set("info", JSONUtil.toJsonStr(entry.getKey())).set("aid", entry.getValue()));
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        // 合并期刊，期刊各元素如果有任一个元素与另一本期刊中相同，则认为是同一本期刊，给予合并成一本期刊。
        List<Set<String>> unionFindList = unionFind(equalSet, spl);
        for (Set<String> set : unionFindList) {
            Set<Integer> aidSet = new HashSet<>();
            // 如果合并后的期刊在多个不重复的期刊中，则将其各期刊对应的aid提取出来后插表，用于后来的人工审核。
            for (Map.Entry<List<String>, Integer> entry : journalListAndAutoIdMap.entrySet()) {
                List<String> list = entry.getKey();
                boolean bool = true;
                for (String s : list) {
                    if (!set.contains(s)) {
                        bool = false;
                        break;
                    }
                }
                if (bool) {
                    aidSet.add(entry.getValue());
                }
            }
            // 如果合并后的期刊，其aidSet.size()为1，说明没有与其它期刊进行合并，如果大于1则说明进行了合并，可以通过aid号进行人工审核。
            try {
                Db.use().insert(Entity.create(detailTable).set("info", JSONUtil.toJsonStr(set)).set("sum", aidSet.size()).set("aid_list", JSONUtil.toJsonStr(aidSet)));
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public static List<Set<String>> unionFind(Set<String> equalSet, String spl) {
        // 手工写的并查集
        List<Set<String>> unionFindList = new ArrayList<>();
        Map<Integer, Set<String>> autoAndAuthSetMap = new HashMap<>();
        Map<String, Integer> authAndAutoMap = new HashMap<>();
        for (String equal : equalSet) {
            List<String> list = Arrays.asList(equal.split(spl));
            int auto = autoAndAuthSetMap.size() + 1;
            Set<Integer> autoSet = new HashSet<>();
            if (!list.isEmpty()) {
                for (String key : list) {
                    if (authAndAutoMap.containsKey(key)) {
                        autoSet.add(authAndAutoMap.get(key));
                    }
                }
                Set<String> all = new HashSet<>();
                if (autoSet.isEmpty()) {
                    all.addAll(list);
                    autoAndAuthSetMap.put(auto, all);
                } else {
                    for (Integer id : autoSet) {
                        if (autoAndAuthSetMap.containsKey(id)) {
                            all.addAll(autoAndAuthSetMap.get(id));
                        }
                        autoAndAuthSetMap.put(id, new HashSet<>());
                    }
                    all.addAll(list);
                    autoAndAuthSetMap.put(auto, all);
                }
                for (String key : all) {
                    authAndAutoMap.put(key, auto);
                }
            }
        }
        for (Map.Entry<Integer, Set<String>> entry : autoAndAuthSetMap.entrySet()) {
            if (!entry.getValue().isEmpty()) {
                unionFindList.add(entry.getValue());
            }
        }
        return unionFindList;
    }


}
